home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Travel to Space
/
Travel to Space.iso
/
dos_prog
/
astronmy
/
epherms
/
plot.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-09-13
|
12KB
|
436 lines
/* code to support the plotting capabilities.
* idea is to let the operator name a plot file and mark some fields for
* logging. then after each screen update, the logged fields are written to
* the plot file. later, the file may be plotted (very simplistically by
* ephem, for now anyway, or by some other program entirely.).
*
* format of the plot file is one line per coordinate: label,x,y
* if z was specified, it is a fourth field.
* x,y,z are plotted using %g format.
*/
#include <stdio.h>
#include <math.h>
#include "screen.h"
extern char *strcpy();
extern errno;
extern char *sys_errlist[];
#define errsys (sys_errlist[errno])
#define TRACE(x) {FILE *fp = fopen("trace","a"); fprintf x; fclose(fp);}
#define MAXPLTLINES 10 /* max number of labeled lines we can track.
* note we can't store more than NFLOGS fields
* anyway (see flog.c).
*/
#define FNLEN (14+1) /* longest filename; plus 1 for \0 */
static char plt_filename[FNLEN] = "ephem.plt"; /* default plot file name */
static FILE *plt_fp; /* the plot file; == 0 means don't plot */
/* store the label and rcfpack()s for each line to track. */
typedef struct {
char pl_label;
int pl_rcpx, pl_rcpy, pl_rcpz;
} PltLine;
static PltLine pltlines[MAXPLTLINES];
static int npltlines; /* number of pltlines[] in actual use */
static int plt_in_polar; /*if true plot in polar coords, else cartesian*/
static int pltsrchfld; /* set when the Search field is to be plotted */
/* picked the Plot label:
* if on, just turn it off.
* if off, turn on, define fields or select name of file to plot and do it.
* TODO: more flexibility, more relevance.
*/
plot_setup()
{
if (plt_fp)
plt_turn_off();
else {
static char *chcs[4] = {
"Select fields", "Display a plot file", (char *)0,
"Begin plotting"
};
static int fn; /* start with 0, then remember for next time */
ask:
chcs[2] = plt_in_polar ? "Polar coords" : "Cartesian coords";
switch (popup(chcs, fn, npltlines > 0 ? 4 : 3)) {
case 0: fn = 0; plt_select_fields(); goto ask;
case 1: fn = 1; plt_file(); goto ask;
case 2: fn = 2; plt_in_polar ^= 1; goto ask;
case 3: fn = 3; plt_turn_on(); break;
default: break;
}
}
}
/* write the active plotfields to the current plot file, if one is open. */
plot()
{
if (plt_fp) {
PltLine *plp;
double x, y, z;
if (!srch_ison() && pltsrchfld) {
/* if searching is not on but we are plotting the search
* funtion we must evaluate and log it ourselves here and now.
* plt_turn_on() insured there is a good function to eval.
* N.B. if searching IS on, we rely on main() having called
* srch_eval() BEFORE plot() so it is already evaluated.
*/
double e;
char errmsg[128];
if (execute_expr (&e, errmsg) < 0) {
f_msg (errmsg);
plt_turn_off();
return;
} else
(void) flog_log (R_SRCH, C_SRCH, e, "");
}
/* plot in order of original selection */
for (plp = pltlines; plp < &pltlines[npltlines]; plp++) {
if (flog_get (plp->pl_rcpx, &x, (char *)0) == 0
&& flog_get (plp->pl_rcpy, &y, (char *)0) == 0) {
(void) fprintf (plt_fp, "%c,%.12g,%.12g", plp->pl_label,
x, y);
if (flog_get (plp->pl_rcpz, &z, (char *)0) == 0)
(void) fprintf (plt_fp, ",%.12g", z);
(void) fprintf (plt_fp, "\n");
}
}
}
}
plot_prstate (force)
int force;
{
static last;
int this = plt_fp != 0;
if (force || this != last) {
f_string (R_PLOT, C_PLOTV, this ? " on" : "off");
last = this;
}
}
plot_ison()
{
return (plt_fp != 0);
}
static
plt_reset()
{
PltLine *plp;
for (plp = &pltlines[npltlines]; --plp >= pltlines; ) {
(void) flog_delete (plp->pl_rcpx);
(void) flog_delete (plp->pl_rcpy);
(void) flog_delete (plp->pl_rcpz);
plp->pl_rcpx = plp->pl_rcpy = plp->pl_rcpz = 0;
}
npltlines = 0;
pltsrchfld = 0;
}
/* let operator select the fields he wants to plot.
* register them with flog and keep rcfpack() in pltlines[] array.
* as a special case, set pltsrchfld if Search field is selected.
*/
static
plt_select_fields()
{
static char hlp[] = "move and RETURN to select a field, or q to quit";
static char sry[] = "Sorry; can not log any more fields.";
int r = R_UT, c = C_UTV; /* TODO: start where main was? */
int sf = rcfpack (R_SRCH, C_SRCH, 0);
char buf[64];
int rcp;
int i;
plt_reset();
for (i = 0; i < MAXPLTLINES; i++) {
(void) sprintf (buf, "select x field for line %d", i+1);
rcp = sel_fld (r, c, alt_menumask()|F_PLT, buf, hlp);
if (!rcp)
break;
if (flog_add (rcp) < 0) {
f_msg (sry);
break;
}
pltlines[i].pl_rcpx = rcp;
if (rcp == sf)
pltsrchfld = 1;
(void) sprintf (buf, "select y field for line %d", i+1);
r = unpackr (rcp); c = unpackc (rcp);
rcp = sel_fld (r, c, alt_menumask()|F_PLT, buf, hlp);
if (!rcp) {
(void) flog_delete (pltlines[i].pl_rcpx);
break;
}
if (flog_add (rcp) < 0) {
(void) flog_delete (pltlines[i].pl_rcpx);
f_msg (sry);
break;
}
pltlines[i].pl_rcpy = rcp;
if (rcp == sf)
pltsrchfld = 1;
(void) sprintf (buf, "select z field for line %d", i+1);
r = unpackr (rcp); c = unpackc (rcp);
rcp = sel_fld (r, c, alt_menumask()|F_PLT, buf, hlp);
if (rcp) {
if (flog_add (rcp) < 0) {
(void) flog_delete (pltlines[i].pl_rcpx);
(void) flog_delete (pltlines[i].pl_rcpy);
f_msg (sry);
break;
}
pltlines[i].pl_rcpz = rcp;
if (rcp == sf)
pltsrchfld = 1;
r = unpackr (rcp); c = unpackc (rcp);
}
do {
(void) sprintf(buf,"enter a one-character label for line %d: ",
i+1);
f_prompt (buf);
} while (read_line (buf, 1) != 1);
pltlines[i].pl_label = *buf;
}
npltlines = i;
}
static
plt_turn_off ()
{
(void) fclose (plt_fp);
plt_fp = 0;
plot_prstate(0);
}
/* turn on plotting.
* establish a file to use (and thereby set plt_fp, the plotting_is_on flag).
* also check that there is a srch function if it is being plotted.
*/
static
plt_turn_on ()
{
int sf = rcfpack(R_SRCH, C_SRCH, 0);
char fn[FNLEN], fnq[NC];
char *optype;
int n;
PltLine *plp;
/* insure there is a valid srch function if we are to plot it */
for (plp = &pltlines[npltlines]; --plp >= pltlines; )
if ((plp->pl_rcpx == sf || plp->pl_rcpy == sf || plp->pl_rcpz == sf)
&& !prog_isgood()) {
f_msg ("Plotting search function but it is not defined.");
return;
}
/* prompt for file name, giving current as default */
(void) sprintf (fnq, "file to write <%s>: ", plt_filename);
f_prompt (fnq);
n = read_line (fn, sizeof(fn)-1);
/* leave plotting off if type END.
* reuse same fn if just type \n
*/
if (n < 0)
return;
if (n > 0)
(void) strcpy (plt_filename, fn);
/* give option to append if file already exists */
optype = "w";
if (access (plt_filename, 2) == 0) {
while (1) {
f_prompt ("files exists; append or overwrite (a/o)?: ");
n = read_char();
if (n == 'a') {
optype = "a";
break;
}
if (n == 'o')
break;
}
}
/* plotting is on if file opens ok */
plt_fp = fopen (plt_filename, optype);
if (!plt_fp) {
char buf[NC];
(void) sprintf (buf, "can not open %s: %s", plt_filename, errsys);
f_prompt (buf);
(void)read_char();
} else {
/* add a title if desired */
static char tp[] = "Title (q to skip): ";
f_prompt (tp);
if (read_line (fnq, PW - sizeof(tp)) > 0)
(void) fprintf (plt_fp, "* %s\n", fnq);
}
plot_prstate (0);
}
/* ask operator for a file to plot. if it's ok, do it.
*/
static
plt_file ()
{
char fn[FNLEN], fnq[64];
FILE *pfp;
int n;
/* prompt for file name, giving current as default */
(void) sprintf (fnq, "file to read <%s>: ", plt_filename);
f_prompt (fnq);
n = read_line (fn, sizeof(fn)-1);
/* forget it if type END.
* reuse same fn if just type \n
*/
if (n < 0)
return;
if (n > 0)
(void) strcpy (plt_filename, fn);
/* do the plot if file opens ok */
pfp = fopen (plt_filename, "r");
if (pfp) {
if (plt_in_polar)
plot_polar (pfp);
else
plot_cartesian (pfp);
(void) fclose (pfp);
} else {
char buf[NC];
(void) sprintf (buf, "can not open %s: %s", plt_filename, errsys);
f_prompt (buf);
(void)read_char();
}
}
/* plot the given file on the screen in cartesian coords.
* TODO: add z tags somehow
* N.B. do whatever you like but redraw the screen when done.
*/
static
plot_cartesian (pfp)
FILE *pfp;
{
static char fmt[] = "%c,%lf,%lf";
double x, y; /* N.B. be sure these match what scanf's %lf wants*/
double minx, maxx, miny, maxy;
char buf[128];
int npts = 0;
char c;
/* find ranges and number of points */
while (fgets (buf, sizeof(buf), pfp)) {
if (sscanf (buf, fmt, &c, &x, &y) != 3)
continue;
if (npts++ == 0) {
maxx = minx = x;
maxy = miny = y;
} else {
if (x > maxx) maxx = x;
else if (x < minx) minx = x;
if (y > maxy) maxy = y;
else if (y < miny) miny = y;
}
}
#define SMALL (1e-10)
if (npts < 2 || fabs(minx-maxx) < SMALL || fabs(miny-maxy) < SMALL)
f_prompt ("At least two different points required to plot.");
else {
/* read file again, this time plotting */
rewind (pfp);
c_erase();
while (fgets (buf, sizeof(buf), pfp)) {
int row, col;
if (sscanf (buf, fmt, &c, &x, &y) != 3)
continue;
row = NR-(int)((NR-1)*(y-miny)/(maxy-miny)+0.5);
col = 1+(int)((NC-1)*(x-minx)/(maxx-minx)+0.5);
if (row == NR && col == NC)
col--; /* avoid lower right scrolling corner */
f_char (row, col, c);
}
/* label axes */
f_double (1, 1, "%g", maxy);
f_double (NR-1, 1, "%g", miny);
f_double (NR, 1, "%g", minx);
f_double (NR, NC-10, "%g", maxx);
}
/* hit any key to resume... */
(void) read_char();
redraw_screen (2); /* full redraw */
}
/* plot the given file on the screen in polar coords.
* first numberic field in plot file is r, second is theta in degrees.
* TODO: add z tags somehow
* N.B. do whatever you like but redraw the screen when done.
*/
static
plot_polar (pfp)
FILE *pfp;
{
static char fmt[] = "%c,%lf,%lf";
double r, th; /* N.B. be sure these match what scanf's %lf wants*/
double maxr;
char buf[128];
int npts = 0;
char c;
/* find ranges and number of points */
while (fgets (buf, sizeof(buf), pfp)) {
if (sscanf (buf, fmt, &c, &r, &th) != 3)
continue;
if (npts++ == 0)
maxr = r;
else
if (r > maxr)
maxr = r;
}
if (npts < 2)
f_prompt ("At least two points required to plot.");
else {
/* read file again, this time plotting */
rewind (pfp);
c_erase();
while (fgets (buf, sizeof(buf), pfp)) {
int row, col;
double x, y;
if (sscanf (buf, fmt, &c, &r, &th) != 3)
continue;
x = r * cos(th/57.2958); /* degs to rads */
y = r * sin(th/57.2958);
row = NR-(int)((NR-1)*(y+maxr)/(2.0*maxr)+0.5);
col = 1+(int)((NC-1)*(x+maxr)/(2.0*maxr)/ASPECT+0.5);
if (row == NR && col == NC)
col--; /* avoid lower right scrolling corner */
f_char (row, col, c);
}
/* label radius */
f_double (NR/2, NC-10, "%g", maxr);
}
/* hit any key to resume... */
(void) read_char();
redraw_screen (2); /* full redraw */
}